﻿// --------------
// 作者:Vitity
// --------------

using NICWebApi.Extensions.DynamicAPI.Filter;
using NICWebApi.Extensions.DynamicAPI.Options;

namespace Microsoft.Extensions.DependencyInjection;

/// <summary>
/// SwaggerExtensions类，用于扩展ASP.NET Core应用程序的Swagger UI配置
/// </summary>
public static class SwaggerExtensions
{
    /// <summary>
    /// 创建SwaggerUI
    /// </summary>
    /// <param name="app"></param>
    /// <returns></returns>
    public static IApplicationBuilder UseDynamicWebApi(this IApplicationBuilder app)
    {
        // 获取DynamicApiOptions配置
        var options = app.ApplicationServices.GetService<DynamicApiOptions>() ?? Utils.GetOptions(); ;

        // 检查是否启用Swagger UI
        if (options?.Swagger.EnableSwaggerUI ?? true)
        {
            // 调用UseSwagger方法，启用Swagger中间件
            app.UseSwagger();

            // 调用UseSwaggerUI方法，并传入配置选项
            app.UseSwaggerUI(c =>
            {
                // 设置Swagger UI的首页HTML文件流
                c.IndexStream = () =>
                {
                    var customIndex = "NICWebApi.Extensions.DynamicAPI.index.html"; // 资源名称
                    StringBuilder htmlBuilder;

                    // 自定义首页模板参数
                    var indexArguments = new Dictionary<string, string>
                    {
                        {"%(VirtualPath)", options?.Swagger.VirtualPath ?? "" } // 使用配置的路由前缀
                    };

                    var assembly = typeof(SwaggerExtensions).Assembly;
                    Stream resourceStream = assembly.GetManifestResourceStream(customIndex);

                    // 如果找不到资源，尝试查找正确的资源名称
                    if (resourceStream == null)
                    {
                        var resourceNames = assembly.GetManifestResourceNames();
                        var resourceName = resourceNames.FirstOrDefault(x => x.EndsWith("index.html"));
                        if (resourceName != null)
                            resourceStream = assembly.GetManifestResourceStream(resourceName);
                        else
                            throw new InvalidOperationException("找不到 Swagger UI 首页模板资源");
                    }

                    // 读取文件内容
                    using (var reader = new StreamReader(resourceStream))
                    {
                        htmlBuilder = new StringBuilder(reader.ReadToEnd());
                    }

                    // 替换模板参数
                    foreach (var (template, value) in indexArguments)
                    {
                        htmlBuilder.Replace(template, value);
                    }

                    // 返回新的内存流
                    var byteArray = Encoding.UTF8.GetBytes(htmlBuilder.ToString());
                    return new MemoryStream(byteArray);
                };

                // 设置Swagger UI的路由前缀，从配置中获取
                c.RoutePrefix = options?.Swagger.RoutePrefix ?? "";

                CreateSwaggerEndpoint(c, options.Swagger);

                // 配置请求前
                //c.UseRequestInterceptor("function(request) { return defaultRequestInterceptor(request); }");
                // 配置请求后
                c.UseResponseInterceptor("function(response) { return defaultResponseInterceptor(response); }");

                // 设置请求时间
                c.DisplayRequestDuration();
                //启用永久授权
                //c.EnablePersistAuthorization();
            });
        }

        // 如果启用了MiniProfiler，则使用MiniProfiler
        if (options?.MiniProfiler.Enabled ?? true)
        {
            // 启用 MiniProfiler组件
            app.UseMiniProfiler();
        }

        return app;
    }

    /// <summary>
    /// 添加SwaggerGen服务
    /// </summary>
    /// <param name="services"></param>
    /// <returns></returns>
    public static IServiceCollection AddSwaggerWithOptions(this IServiceCollection services)
    {
        // 添加API探索器服务
        services.AddEndpointsApiExplorer();

        // 获取服务提供者
        var serviceProvider = services.BuildServiceProvider();
        // 获取DynamicApiOptions配置
        var options = serviceProvider.GetService<DynamicApiOptions>() ?? Utils.GetOptions(); ;
        // 获取Swagger配置选项
        var swaggerOptions = options?.Swagger;

        // 添加Swagger生成器服务
        services.AddSwaggerGen(c =>
        {
            CreateSwaggerDocs(c, swaggerOptions);

            CreateSwaggerXmls(c);

            #region 设置Swagger授权信息

            ConfigureSecurities(c, swaggerOptions);

            #endregion 设置Swagger授权信息

            #region 设置Swagger分组信息

            c.DocInclusionPredicate(CheckApiDescriptionInCurrentGroup);

            #endregion 设置Swagger分组信息

            #region 设置action排序

            c.OrderActionsBy(c =>
            {
                var setting = c.CustomAttributes()
                                      .FirstOrDefault(u => u.GetType() == typeof(ApiSettingAttribute))
                                      as ApiSettingAttribute ?? new ApiSettingAttribute();

                return (int.MaxValue - setting.Order).ToString()
                                .PadLeft(int.MaxValue.ToString().Length, '0');
            });

            #endregion 设置action排序

            // 20250929 因相同引用类名造成异常情况
            c.CustomSchemaIds((type) => type.FullName);
            // 添加操作过滤器，用于自定义Swagger响应
            c.OperationFilter<SwaggerOperationFilter>();
            c.DocumentFilter<SwaggerDocumentFilter>();
        });
        return services;
    }

    /// <summary>
    /// 使用配置选项添加MiniProfiler服务
    /// </summary>
    /// <param name="services">服务集合</param>
    public static IServiceCollection AddMiniProfilerWithOptions(this IServiceCollection services)
    {
        // 获取DynamicApiOptions
        var serviceProvider = services.BuildServiceProvider();
        var options = serviceProvider.GetService<DynamicApiOptions>() ?? Utils.GetOptions();
        var miniProfilerOptions = options?.MiniProfiler;

        // 如果MiniProfiler未启用，则直接返回
        if (miniProfilerOptions != null && !miniProfilerOptions.Enabled)
        {
            return services;
        }

        // 添加MiniProfiler服务，使用配置选项
        services.AddMiniProfiler(options =>
        {
            // 设置访问分析结果URL的路由基地址
            options.RouteBasePath = miniProfilerOptions?.RouteBasePath ?? "/profiler";

            // 设置是否启用MVC过滤器分析
            options.EnableMvcFilterProfiling = miniProfilerOptions?.EnableMvcFilterProfiling ?? false;

            // 设置是否启用MVC视图分析
            options.EnableMvcViewProfiling = miniProfilerOptions?.EnableMvcViewProfiling ?? false;

            // 设置颜色方案
            options.ColorScheme = GetColorScheme(miniProfilerOptions?.ColorScheme);

            // 设置弹出框位置
            options.PopupRenderPosition = GetRenderPosition(miniProfilerOptions?.PopupRenderPosition);

            // 设置是否显示子时间
            options.PopupShowTimeWithChildren = miniProfilerOptions?.PopupShowTimeWithChildren ?? true;

            // 设置是否显示琐碎信息
            options.PopupShowTrivial = miniProfilerOptions?.PopupShowTrivial ?? true;

            // 设置SQL格式化器
            options.SqlFormatter = new InlineFormatter();
        });

        // 如果启用了Entity Framework分析，则添加Entity Framework支持
        if (miniProfilerOptions?.EnableEntityFrameworkProfiling ?? true)
        {
            services.AddMiniProfiler().AddEntityFramework();
        }
        return services;
    }

    /// <summary>
    /// 获取MiniProfiler颜色方案
    /// </summary>
    /// <param name="colorScheme">颜色方案名称</param>
    /// <returns>颜色方案枚举值</returns>
    private static ColorScheme GetColorScheme(string colorScheme)
    {
        return colorScheme?.ToLowerInvariant() switch
        {
            "light" => ColorScheme.Light,
            "dark" => ColorScheme.Dark,
            "auto" or _ => ColorScheme.Auto
        };
    }

    /// <summary>
    /// 获取MiniProfiler渲染位置
    /// </summary>
    /// <param name="position">位置名称</param>
    /// <returns>渲染位置枚举值</returns>
    private static RenderPosition GetRenderPosition(string position)
    {
        return position?.ToLowerInvariant() switch
        {
            "left" => RenderPosition.Left,
            "right" => RenderPosition.Right,
            "bottomleft" => RenderPosition.BottomLeft,
            "bottomright" => RenderPosition.BottomRight,
            _ => RenderPosition.Left
        };
    }

    /// <summary>
    /// 检查ApiDescription是否在当前分组中
    /// </summary>
    /// <param name="currentGroup"></param>
    /// <param name="apiDescription"></param>
    /// <returns></returns>
    public static bool CheckApiDescriptionInCurrentGroup(string currentGroup, ApiDescription apiDescription)
    {
        if (!apiDescription.TryGetMethodInfo(out var method)) return false;

        if (!Utils.ActionDict.TryGetValue(method, out var actionMeta))
        {
            // 如果ActionMeta都没有，只有Default分组才返回true，否则false
            return currentGroup == Utils.DefaultGroupName;
        }

        // 如果ActionMeta有分组，且包含当前分组
        if (actionMeta.Groups != null && actionMeta.Groups.Contains(currentGroup))
            return true;

        // 如果没有分组，且当前分组是Default
        if ((actionMeta.Groups == null || actionMeta.Groups.Length == 0) && currentGroup == Utils.DefaultGroupName)
            return true;

        return false;
    }

    /// <summary>
    /// 创建Swagger文档
    /// </summary>
    /// <param name="c"></param>
    /// <param name="swaggerOptions"></param>
    public static void CreateSwaggerDocs(SwaggerGenOptions c, SwaggerBuildOptions swaggerOptions)
    {
        var groupList = Utils.ActionGroups;
        if (groupList != null || groupList.Count() > 0)
        {
            foreach (var group in groupList)
            {
                if (c.SwaggerGeneratorOptions.SwaggerDocs.ContainsKey(group)) continue;

                #region 设置Swagger文档信息

                // 设置Swagger文档信息
                c.SwaggerDoc(group, new OpenApiInfo
                {
                    Version = "v1",
                    Title = swaggerOptions?.Title ?? "API Documentation",
                    Description = swaggerOptions?.Description ?? "An ASP.NET Core Web API",
                    TermsOfService = new Uri(swaggerOptions?.TermsOfServiceUrl ?? "https://example.com/terms"),
                    Contact = new OpenApiContact
                    {
                        Name = swaggerOptions?.Contact.Name ?? "API Support",
                        Url = new Uri(swaggerOptions?.Contact.Url ?? "https://example.com/contact"),
                        Email = swaggerOptions?.Contact.Email
                    },
                    License = new OpenApiLicense
                    {
                        Name = swaggerOptions?.License.Name ?? "License",
                        Url = new Uri(swaggerOptions?.License.Url ?? "https://example.com/license")
                    }
                });

                #endregion 设置Swagger文档信息
            }
        }
    }

    /// <summary>
    /// 创建SwaggerXmls
    /// </summary>
    /// <param name="c"></param>
    public static void CreateSwaggerXmls(SwaggerGenOptions c)
    {
        #region 获取引用项目生成文件夹中的所有xml文件

        // 获取引用项目生成文件夹中的所有xml文件
        var xmlFiles = Utils.GetXmlFiles();

        foreach (var item in xmlFiles)
        {
            c.IncludeXmlComments(item, true);
        }

        #endregion 获取引用项目生成文件夹中的所有xml文件
    }

    /// <summary>
    /// 配置授权信息
    /// </summary>
    /// <param name="c"></param>
    /// <param name="swaggerOptions"></param>
    public static void ConfigureSecurities(SwaggerGenOptions c, SwaggerBuildOptions swaggerOptions)
    {
        // 检查是否启用授权
        if (swaggerOptions?.EnableAuthorized ?? true)
        {
            // 添加Bearer认证方式
            c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme()
            {
                Type = SecuritySchemeType.Http,
                Name = "Authorization",
                Description = "JWT Authorization header using the Bearer scheme.",
                BearerFormat = "JWT",
                Scheme = "bearer",
                In = ParameterLocation.Header
            });
            // 添加安全要求
            c.AddSecurityRequirement(new OpenApiSecurityRequirement
                {
                    {
                        new OpenApiSecurityScheme
                        {
                            Reference = new OpenApiReference()
                            {
                                Type = ReferenceType.SecurityScheme,
                                Id = "Bearer"
                            }
                        },
                        new string[]{}
                    }
                });
            // 添加操作过滤器
            c.OperationFilter<AddResponseHeadersFilter>();
            c.OperationFilter<AppendAuthorizeToSummaryOperationFilter>();
            // 在header中添加token，传递到后台
            c.OperationFilter<SecurityRequirementsOperationFilter>();
        }
    }

    /// <summary>
    /// 创建Swagger UI的文档选择器
    /// </summary>
    /// <param name="c"></param>
    /// <param name="swaggerOptions"></param>
    public static void CreateSwaggerEndpoint(SwaggerUIOptions c, SwaggerBuildOptions swaggerOptions)
    {
        var groupList = Utils.ActionGroups;
        if (groupList != null || groupList.Count() > 0)
        {
            // 先添加Default分组
            if (groupList.Contains(Utils.DefaultGroupName))
            {
                c.SwaggerEndpoint($"{swaggerOptions.VirtualPath ?? ""}/swagger/{Utils.DefaultGroupName}/swagger.json", Utils.DefaultGroupName);
            }
            // 再添加其他分组
            foreach (var group in groupList)
            {
                if (group != Utils.DefaultGroupName)
                {
                    c.SwaggerEndpoint($"{swaggerOptions.VirtualPath ?? ""}/swagger/{group}/swagger.json", group);
                }
            }
        }
    }
}